/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * uniview
 * Copyright (C) Michael J. Beer 2010 <michael.josef.beer@googlemail.com>
 * 
 * uniview is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * uniview is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _TRANSFORMATION_HH_
#define _TRANSFORMATION_HH_

#include "Point.h"
#include "Matrix.h"
#include <cstring>

namespace uniview {

    /**
     * This class represents a transformation of the Kind
     * m . a + translation
     * where m is a square matrix 
     * translation is a vector
     */
    class Transformation {
        public:

            Transformation();

            Transformation(int m, int n);

            Transformation(int m , int n, double **matrix, double *translation);

            ~Transformation();            
            
            
            /**
             * Assigns new transformation that rotates round x axis
             *  angle rotate angle in rad
             */
            Transformation *rotateX(double angle);
            
            
            /**
             * Assigns new transformation that rotates round y axis
             *  angle rotate angle in rad
             */
            Transformation *rotateY(double angle);
            
            
            /**
             * Assigns new transformation that rotates round z axis
             *  angle rotate angle in rad
             */
            Transformation *rotateZ(double angle);
            
            
            /**
             * Gives a transformation that transforms the point origin to (0,0,0) 
             * and aligns the vector a to (|a|,0,0)
             * This works for 3 dim only
             */
            static Transformation *getAlignToXAxis(double *a, double *origin) {
                Transformation *trans = new Transformation(3, 3);
                return trans->alignToXAxis(a, origin);
            };


            /**
             * Sets transformation this way that the the point origin 
             * is tranferred to (0,0,0) 
             * and the vector a is aligned to (|a|,0,0)
             * This works for 3 dim only
             */
            Transformation *alignToXAxis(double *a, double *origin);


            inline double *apply(double *a, double *res) {
                for(int i = 0; i < m; i++) {
                    res[i] = 0.0;
                    for(int j = 0; j < n; j++) {
                        res[i] += this->matrix[i][j] * a[j];
                    };
                };

                for(int i = 0; i < m; i++) {
                    res[i] += this->translation[i];
                };
                return res;
            };


            inline double *apply(double *a) {
                double *res = Point::newPoint(m);
                return apply(a, res);
            };
            
            
            inline double **apply(double **a, int no, double **res) {
                for(int i = 0; i < no; i++) {
                    this->apply(a[i], res[i]);
                }
                return res;
            };

            double **getMatrix() {
                return matrix;
            };
            
            double *getTranslation() {
                return translation;
            };
            

            int getM() {
                return m;
            };

            int getN() {
                return n;
            };
                
        protected:
            int m, n;
            double **matrix;
            double *translation;
            
            void init(int m, int n);            
    };

};

#endif // _TRANSFORMATION_HH_